#include"graph.h"
using namespace std;


Straight::Straight(Dot* a, Dot* b, string c) :Line(a, b, c) {         //直线的构造函数
	double x1 = a->x;
	double x2 = b->x;
	double y1 = a->y;
	double y2 = b->y;
	length = sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
	slope = (y2 - y1) / (x2 - x1);
	intercept = y1 - slope * x1;
	Ray* ra = new Ray(b, this->length);
	Ray* rb = new Ray(a, this->length);
	a->Connection.push_back(*ra);         //构建邻接表
	b->Connection.push_back(*rb);
	this->type = 1;
}

OrdinaryDot* CreateOrdinaryDot(double x, double y) {       //选择地图上相应的点，根据坐标构建普通点（仅限管理员功能）
	OrdinaryDot* p = new OrdinaryDot(DotID, x, y);
	DotID++;
	return p;
}

Scenery* CreateScenery(double x, double y, string name) {       //输入景点名字，选择地图上相应的点，根据坐标构建景点（仅限管理员功能）
	Scenery* p = new Scenery(DotID, x, y, name);
	if (SceneryKu.find(name) == SceneryKu.end()) {
		throw "Error:The name has been occupied.";              //如果景点名字重复，进行异常处理
	}
	DotID++;
	return p;
}

//注意：前后端衔接过程中可能需要自行再写查找函数以查找鼠标点的坐标对应的是哪个点，再把这个点作为形参执行相应功能。

Crossroad* CreateCrossroad(double x, double y) {       //选择地图上相应的点，根据坐标构建十字路口（仅限管理员功能）
	Crossroad* p = new Crossroad(DotID, x, y);
	DotID++;
	return p;
}

BusStation* CreateBusStation(double x, double y) {       //选择地图上相应的点，根据坐标构建公交站点（仅限管理员功能）
	BusStation* p = new BusStation(DotID, x, y);
	DotID++;
	return p;
}

void Set_portrait(Scenery& s, string p) {           //创建或修改景点的描述（仅限管理员功能）
	s.portrait = p;
}

void Set_portrait(Dot& s, string p) {           //创建或修改景点的描述（仅限管理员功能）
	s.portrait = p;
}

void Set_portrait(Dot* s, string p) {           //创建或修改景点的描述（仅限管理员功能）
	s->portrait = p;
}


bool operator >(Scenery a, Scenery b) {          //运算符重载，方便对查询到的景点按字数长度进行排序
	return a.name.size() > b.name.size() ? 1 : 0;
}
bool operator <(Scenery a, Scenery b) {
	return a.name.size() < b.name.size() ? 1 : 0;
}
bool operator ==(Scenery a, Scenery b) {
	return a.name.size() == b.name.size() ? 1 : 0;
}
bool operator >=(Scenery a, Scenery b) {
	return a.name.size() >= b.name.size() ? 1 : 0;
}
bool operator <=(Scenery a, Scenery b) {
	return a.name.size() <= b.name.size() ? 1 : 0;
}

vector<Dot*> InquireScenery(string t) {              //查询景点,利用KMP算法(用户或管理员均可使用）
	vector<Dot*>F;
	map<string, Dot*>::iterator it = SceneryKu.find(t);
	if (it != SceneryKu.end()) {        //查询成功
		F.push_back(it->second);
		return F;
	}
	else {                 //使用KMP算法查询模式串是否有匹配的景点
		for (map<string, Dot*>::iterator it2 = SceneryKu.begin(); it2 != SceneryKu.end(); it2++) {
			if (KMP(it2->second->name, t) == 1) {
				F.push_back(it2->second);
			}
		}
		sort(F.begin(), F.end());     //给景点库按照匹配程度进行排序（即按照景点名字长度降序排序)
		return F;
	}
}

void DeleteDot(int x, int y) {            //传入待删除点的坐标，删除此点(做界面的时候可能还需要加入界面处理的一些操作）（仅限管理员功能）
	vector<Dot*>::iterator it = DotKu.begin();
	for (; it != DotKu.end(); it++) {
		if (((*it)->x) - x <= eps && ((*it)->y) - y <= eps) {
			if ((*it)->type == 2) {       //表示这个点是景点，需要从景点库中删除它
				SceneryKu.erase((*it)->Getname());
			}
			(*it)->~Dot();     //调用析构函数
			DotKu.erase(it);
			break;
		}
	}
	//if (it == DotKu.end()) {   //it被删后已经没意义了
	//	throw"Error:Program Exception";      //异常处理，一般情况删除点需要点击那个点，必定会找到点的
	//}
	for (int i = 0; i < DotKu.size(); i++) {           //删除后，部分点在库中下标会发生改变，因此需要加以修改
		DotSearch[DotKu[i]] = i;
	}
	return;
}

Straight* CreateStraight(Dot* a, Dot* b, string name) {    //根据直线的两个端点并输入道路的名字，创建直线(做界面的时候可能还需要加入界面处理的一些操作）（仅限管理员功能）
	Straight* p = new Straight(a, b, name);
	return p;
}

void DeleteStraight(Dot* a, Dot* b) {   //传入待删除直线所连接的两个点，删除对应的直线(做界面的时候可能还需要加入界面处理的一些操作）（仅限管理员功能）
	vector<Line*>::iterator it = LineKu.begin();
	for (; it != LineKu.end(); it++) {
		if ((((*it)->Edge1 == a && (*it)->Edge2 == b) || ((*it)->Edge1 == b && (*it)->Edge2 == a)) && (*it)->type == 1) {
			(*it)->~Line();     //调用析构函数
			LineKu.erase(it);
			break;
		}
	}
	if (it == LineKu.end()) {
		throw"Error:Program Exception";      //异常处理，没有找到待删除的线
	}
	return;
}

void DeleteStraight(string name) {   //重载函数：传入道路的名字，删除对应的直线（仅限管理员功能）
	vector<Line*>::iterator it = LineKu.begin();
	for (; it != LineKu.end(); it++) {
		if ((*it)->Getname() == name) {
			(*it)->~Line();     //调用析构函数
			LineKu.erase(it);
			break;
		}
	}
	//if (it == LineKu.end()) {    //这句话不删必有bug！因为it已经被删除，无意义了
	//	throw"Error:Program Exception";      //异常处理，没有找到待删除的线
	//}
	return;
}
//备注：两点之间只可确定一条直线，但经过两点存在无穷多条曲线，后期进行曲线功能扩展时会加入曲线的构造和删除功能，需要传入相应的函数解析式

void SetCrossroadPassingTime(Crossroad& cro, Time Start, Time GreenDuration) {         //设置十字路口通行的时间,第一个参数为待设置的十字路口，第二个参数是路口第一象限方向第一个绿灯起始时间，第三个参数是每个路口绿灯时长（仅限管理员功能）
	while (Start >= GreenDuration) {
		Start = Start - GreenDuration;
	}
	vector<Period>K;
	for (Time Status = Start;; Status = Status + GreenDuration) {
		if (Status.layer == 1) {
			break;
		}
		Period* p = new Period(Status, Status + GreenDuration);
		K.push_back(*p);
	}
	int sum = K.size();
	vector<Period>K1;
	vector<Period>K2;
	vector<Period>K3;
	vector<Period>K4;
	for (int i = 0; i < sum; i += 4) {
		K1.push_back(K[i]);
	}
	for (int i = 1; i < sum; i += 4) {
		K2.push_back(K[i]);
	}
	for (int i = 2; i < sum; i += 4) {
		K3.push_back(K[i]);
	}
	for (int i = 3; i < sum; i += 4) {
		K4.push_back(K[i]);
	}
	cro.SetPassingTime(K1, K2, K3, K4);
	return;
}


